from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.db.postgres import get_session
from app.db.mongo import db
# 不再依赖报告文档创建；使用 EvaluationReport.id 作为会话与运行的 report_id 引用
from app.models import EvaluationReport
from bson import ObjectId
import datetime
import uuid


router = APIRouter(prefix="/report-content", tags=["report-content"])


@router.get("/{version_id}/sections/{section_no}/tasks")
async def list_tasks(version_id: str, section_no: str, session: AsyncSession = Depends(get_session)):
    v = await session.get(EvaluationReport, version_id)
    if not v:
        raise HTTPException(status_code=404, detail="version_not_found")
    report_id = str(v.id)
    cur = db.section_conversations.find({"report_id": report_id, "section_no": section_no}).sort("created_at", -1)
    items = []
    async for x in cur:
        items.append({
            "id": str(x.get("_id")),
            "conversation_id": x.get("conversation_id"),
            "title": x.get("title"),
            "meta": "任务"
        })
    return {"items": items}


@router.post("/{version_id}/sections/{section_no}/tasks")
async def create_task(version_id: str, section_no: str, payload: dict, session: AsyncSession = Depends(get_session)):
    v = await session.get(EvaluationReport, version_id)
    if not v:
        raise HTTPException(status_code=404, detail="version_not_found")
    report_id = str(v.id)
    title = payload.get("title") or ""
    conv_id = str(uuid.uuid4())
    doc = {
        "report_id": report_id,
        "section_no": section_no,
        "conversation_id": conv_id,
        "title": title,
        "messages": [],
        "created_at": datetime.datetime.utcnow(),
    }
    r = await db.section_conversations.insert_one(doc)
    return {"id": str(r.inserted_id), "conversation_id": conv_id, "title": title, "meta": "任务"}


@router.put("/{version_id}/sections/{section_no}/tasks/{task_id}")
async def rename_task(version_id: str, section_no: str, task_id: str, payload: dict, session: AsyncSession = Depends(get_session)):
    v = await session.get(EvaluationReport, version_id)
    if not v:
        raise HTTPException(status_code=404, detail="version_not_found")
    report_id = str(v.id)
    title = payload.get("title") or ""
    r = await db.section_conversations.update_one({"_id": ObjectId(task_id), "report_id": report_id, "section_no": section_no}, {"$set": {"title": title}})
    if r.matched_count == 0:
        raise HTTPException(status_code=404, detail="task_not_found")
    return {"ok": True}


@router.delete("/{version_id}/sections/{section_no}/tasks/{task_id}")
async def delete_task(version_id: str, section_no: str, task_id: str, session: AsyncSession = Depends(get_session)):
    v = await session.get(EvaluationReport, version_id)
    if not v:
        raise HTTPException(status_code=404, detail="version_not_found")
    report_id = str(v.id)
    r = await db.section_conversations.delete_one({"_id": ObjectId(task_id), "report_id": report_id, "section_no": section_no})
    if r.deleted_count == 0:
        raise HTTPException(status_code=404, detail="task_not_found")
    return {"ok": True}


@router.get("/{version_id}/sections/{section_no}/tasks/{task_id}/messages")
async def list_messages(
    version_id: str,
    section_no: str,
    task_id: str,
    limit: int = Query(20, ge=1, le=200),
    before: str | None = None,
    session: AsyncSession = Depends(get_session)
):
    v = await session.get(EvaluationReport, version_id)
    if not v:
        raise HTTPException(status_code=404, detail="version_not_found")
    report_id = str(v.id)
    doc = await db.section_conversations.find_one({"_id": ObjectId(task_id), "report_id": report_id, "section_no": section_no})
    if not doc:
        raise HTTPException(status_code=404, detail="task_not_found")
    msgs = list(doc.get("messages") or [])

    report_doc = None
    if getattr(v, "mongo_report_id", None):
        try:
            report_doc = await db.reports.find_one({"_id": ObjectId(v.mongo_report_id)})
        except Exception:
            report_doc = None

    def _to_dt(m):
        dt = m.get("created_at")
        if isinstance(dt, datetime.datetime):
            return dt
        try:
            return datetime.datetime.fromisoformat(str(dt))
        except Exception:
            return datetime.datetime.min

    msgs.sort(key=_to_dt)
    if before:
        try:
            before_dt = datetime.datetime.fromisoformat(before)
            msgs = [m for m in msgs if _to_dt(m) < before_dt]
        except Exception:
            pass
    total = len(msgs)
    slice_items = msgs[-limit:] if total > limit else msgs
    has_more = total > len(slice_items)
    next_before = _to_dt(slice_items[0]).isoformat() if slice_items else None
    items = []
    for m in slice_items:
        cand_id = m.get("candidate_id")
        if not cand_id and m.get("role") == "assistant" and report_doc:
            try:
                sec = next((s for s in (report_doc.get("sections") or []) if s.get("section_no") == section_no), None)
                if sec:
                    for c in (sec.get("content", {}).get("candidates", []) or []):
                        if (c or {}).get("text") == m.get("content"):
                            cand_id = c.get("candidate_id")
                            break
            except Exception:
                pass
        items.append({
            "msg_id": m.get("msg_id") or str(uuid.uuid4()),
            "role": m.get("role"),
            "text": m.get("content"),
            "candidate_id": cand_id,
            "created_at": _to_dt(m).isoformat(),
        })
    return {"items": items, "has_more": has_more, "next_before": next_before}


@router.delete("/{version_id}/sections/{section_no}/tasks/{task_id}/messages/{msg_id}")
async def delete_message_pair(version_id: str, section_no: str, task_id: str, msg_id: str, session: AsyncSession = Depends(get_session)):
    v = await session.get(EvaluationReport, version_id)
    if not v:
        raise HTTPException(status_code=404, detail="version_not_found")
    report_id = str(v.id)
    doc = await db.section_conversations.find_one({"_id": ObjectId(task_id), "report_id": report_id, "section_no": section_no})
    if not doc:
        raise HTTPException(status_code=404, detail="task_not_found")
    msgs = list(doc.get("messages") or [])
    idx = next((i for i, m in enumerate(msgs) if str(m.get("msg_id")) == str(msg_id)), -1)
    if idx < 0:
        raise HTTPException(status_code=404, detail="message_not_found")
    if (msgs[idx] or {}).get("role") != "user":
        raise HTTPException(status_code=400, detail="not_user_message")
    end = idx + 1
    while end < len(msgs) and (msgs[end] or {}).get("role") == "assistant":
        end += 1
    new_msgs = msgs[:idx] + msgs[end:]
    await db.section_conversations.update_one({"_id": ObjectId(task_id)}, {"$set": {"messages": new_msgs}})
    return {"ok": True}
